﻿// <author>Netmon Cipher Dev Team</author>
// <date>2009-07-16</date>
// <version>1.0</version>
// <summary>This contains the Utility functions.</summary>

namespace SSLDecryptionExpert
{
    using System;
    using System.IO;

    /// <summary>
    /// Utility Class
    /// </summary>
    public static class Utils
    {
        /// <summary>
        /// Creates the directory if it does not exist.
        /// </summary>
        /// <param name="pathToSearch">
        /// Directory path to find.
        /// </param>
        /// <returns>
        /// Returns True if Directory already exists or is created.
        /// </returns>
        public static bool CreateDirectoryIfNotExists(string pathToSearch)
        {
            string directory = GetDirectory(pathToSearch);

            if (!Directory.Exists(directory))
            {
                try
                {
                    Directory.CreateDirectory(directory);
                }
                catch (IOException)
                {
                    return false;
                }
                catch (UnauthorizedAccessException)
                {
                    return false;
                }
            }

            return true;
        }

        /// <summary>
        /// Gets the directory of the file specified.
        /// </summary>
        /// <param name="filePath">
        /// File to check.
        /// </param>
        /// <returns>
        /// Returns Directory path.
        /// </returns>
        public static string GetDirectory(string filePath)
        {
            if (string.IsNullOrEmpty(filePath))
            {
                return string.Empty;
            }

            string directory = string.Empty;

            for (int dirLen = filePath.Length - 1; dirLen > 0; dirLen--)
            {
                if (filePath[dirLen] == '\\')
                {
                    directory = filePath.Substring(0, dirLen + 1);
                    break;
                }
            }

            return directory;
        }

        /// <summary>
        /// Gets Ip address from string format
        /// </summary>
        /// <param name="strIpAddress">IP Address in string format</param>
        /// <param name="arrIPAddress">IP Address</param>
        /// <returns>Returns TRUE if conversion is successful</returns>
        public static bool GetIpFromString(string strIpAddress, out byte[] arrIPAddress)
        {
            bool result = false;

            if (string.IsNullOrEmpty(strIpAddress))
            {
                arrIPAddress = null;
                return result;
            }

            string[] strIpv4 = strIpAddress.Split('.');
            if (strIpv4.Length == 4 && !strIpv4[0].Contains(":"))
            {
                byte[] ip4 = new byte[4];
                for (int i = 0; i < 4; i++)
                {
                    ip4[i] = (byte)Convert.ToInt16(strIpv4[i], 10);
                }

                arrIPAddress = ip4;
                return true;
            }

            string[] strIpv6 = strIpAddress.Split(':');
            if (strIpv6.Length == 8)
            {
                byte[] ip6 = new byte[2 * strIpv6.Length];
                for (int i = 0; i < 8; i++)
                {
                    switch (strIpv6[i].Length)
                    {
                        case 1:
                            ip6[i * 2] = (byte)0;
                            ip6[(i * 2) + 1] = (byte)Convert.ToInt16(strIpv6[i], 16);
                            break;
                        case 2:
                            ip6[i * 2] = (byte)0;
                            ip6[(i * 2) + 1] = (byte)Convert.ToInt16(strIpv6[i], 16);
                            break;

                        case 3:
                            ip6[i * 2] = (byte)Convert.ToInt16(strIpv6[i].Substring(0, 1), 16);
                            ip6[(i * 2) + 1] = (byte)Convert.ToInt16(strIpv6[i].Substring(1, 2), 16);
                            break;

                        case 4:
                            ip6[i * 2] = (byte)Convert.ToInt16(strIpv6[i].Substring(0, 2), 16);
                            ip6[(i * 2) + 1] = (byte)Convert.ToInt16(strIpv6[i].Substring(2, 2), 16);
                            break;
                    }
                }

                arrIPAddress = ip6;
                return true;
            }
            else if (strIpv6.Length == 7) // IPv4-mapped address
            {
                byte[] ip6 = new byte[2 * (strIpv6.Length+1)];

                for (int i = 0; i < 7; i++)
                {
                    switch (strIpv6[i].Length)
                    {
                        case 1:
                            ip6[i * 2] = (byte)0;
                            ip6[(i * 2) + 1] = (byte)Convert.ToInt16(strIpv6[i], 16);
                            break;
                        case 2:
                            ip6[i * 2] = (byte)0;
                            ip6[(i * 2) + 1] = (byte)Convert.ToInt16(strIpv6[i], 16);
                            break;
                        case 3:
                            ip6[i * 2] = (byte)Convert.ToInt16(strIpv6[i].Substring(0, 1), 16);
                            ip6[(i * 2) + 1] = (byte)Convert.ToInt16(strIpv6[i].Substring(1, 2), 16);
                            break;

                        case 4:
                            ip6[i * 2] = (byte)Convert.ToInt16(strIpv6[i].Substring(0, 2), 16);
                            ip6[(i * 2) + 1] = (byte)Convert.ToInt16(strIpv6[i].Substring(2, 2), 16);
                            break;
                        default:
                            // In this case we have a dotted address, 192.168.1.1, we'll need to convert.
                            strIpv4 = strIpv6[i].Split('.');
                            ip6[i * 2] = (byte)Convert.ToInt16(strIpv4[0], 16);
                            ip6[(i * 2) + 1] = (byte)Convert.ToInt16(strIpv4[1], 16);
                            ip6[(i * 2) + 2] = (byte)Convert.ToInt16(strIpv4[2], 16);
                            ip6[(i * 2) + 3] = (byte)Convert.ToInt16(strIpv4[3], 16);
                            break;
                    }
                }

                arrIPAddress = ip6;
                return true;
            }

            arrIPAddress = null;
            return result;
        }

        #region Append Arrays

        /// <summary>
        /// This Method is used to append two byte arrays
        /// </summary>
        /// <param name="originalArray">
        /// Original array after which the second array is appened</param>
        /// <param name="arraytoAppend">
        /// Array which is appended to the original</param>
        public static void AppendArray(
                                ref byte[] originalArray,
                                byte[] arraytoAppend)
        {
            if (originalArray == null)
            {
                return;
            }

            if (arraytoAppend == null)
            {
                return;
            }

            byte[] newArray = new byte[originalArray.Length + arraytoAppend.Length];
            Array.Copy(originalArray, 0, newArray, 0, originalArray.Length);
            Array.Copy(arraytoAppend, 0, newArray, originalArray.Length, arraytoAppend.Length);
            originalArray = newArray;
        }

        /// <summary>
        /// This Method is used to append two byte arrays with offset
        /// </summary>
        /// <param name="originalArray">
        /// Original array after which the second array is appened</param>
        /// <param name="arraytoAppend">
        /// array which is appended to the original</param>
        /// <param name="offset">Offset where array is to be appended</param>
        public static void AppendArray(
                                ref byte[] originalArray,
                                byte[] arraytoAppend,
                                int offset)
        {
            if (originalArray == null)
            {
                return;
            }

            if (arraytoAppend == null)
            {
                return;
            }

            byte[] newArray = new byte[originalArray.Length + offset];
            Array.Copy(originalArray, 0, newArray, 0, originalArray.Length);
            Array.Copy(arraytoAppend, 0, newArray, originalArray.Length, offset);
            originalArray = newArray;
        }

        #endregion

        #region Compare Arrays

        /// <summary>
        /// This method compares two arrays
        /// </summary>
        /// <param name="arrayOne">
        /// First array to be compared
        /// </param>
        /// <param name="arrayTwo">
        /// Second array to be compared
        /// </param>
        /// <returns>
        /// True, if two arrays are same
        /// False, if not
        /// </returns>
        public static bool CompareArrays(byte[] arrayOne, byte[] arrayTwo)
        {
            if (arrayOne == null)
            {
                return false;
            }

            if (arrayTwo == null)
            {
                return false;
            }

            if (arrayOne.Length != arrayTwo.Length)
            {
                return false;
            }

            for (int index = 0; index < arrayOne.Length; index++)
            {
                if (arrayOne[index] != arrayTwo[index])
                {
                    return false;
                }
            }

            return true;
        }

        #endregion                
    }
}
